package com.sikaryofficial.backend.manager;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.google.common.collect.Lists;
import com.sikaryofficial.backend.constant.RedisCacheKey;
import com.sikaryofficial.backend.constant.ReportBusinessTypeEnum;
import com.sikaryofficial.backend.domain.dto.req.ProductDeleteReq;
import com.sikaryofficial.backend.domain.dto.req.content.ContentDeleteReq;
import com.sikaryofficial.backend.domain.entity.ArticleEvaluate;
import com.sikaryofficial.backend.domain.entity.ArticleEvaluateReply;
import com.sikaryofficial.backend.domain.entity.BrandTaste;
import com.sikaryofficial.backend.domain.entity.BrandTasteEvaluate;
import com.sikaryofficial.backend.domain.entity.BrandTasteEvaluateReply;
import com.sikaryofficial.backend.domain.entity.MyStatistics;
import com.sikaryofficial.backend.domain.entity.Store;
import com.sikaryofficial.backend.domain.entity.StoreFollow;
import com.sikaryofficial.backend.domain.entity.UserAction;
import com.sikaryofficial.backend.mapper.BrandTasteMapper;
import com.sikaryofficial.backend.service.IArticleEvaluateReplyService;
import com.sikaryofficial.backend.service.IArticleEvaluateService;
import com.sikaryofficial.backend.service.IBrandTasteEvaluateReplyService;
import com.sikaryofficial.backend.service.IBrandTasteEvaluateService;
import com.sikaryofficial.backend.service.IBrandTasteService;
import com.sikaryofficial.backend.service.IMyStatisticsService;
import com.sikaryofficial.backend.service.IStoreFollowService;
import com.sikaryofficial.backend.service.IStoreService;
import com.sikaryofficial.backend.service.IUserActionService;
import com.sikaryofficial.backend.service.article.cache.ReceivedLikesCacheService;
import com.sikaryofficial.backend.service.brand.cache.BrandTasteCacheService;
import com.sikaryofficial.common.core.exception.ServiceException;
import com.sikaryofficial.common.redis.service.RedisService;
import com.sikaryofficial.common.security.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.sikaryofficial.backend.constant.ProductConstant.SOURCE_USER_EVALUATE;

/**
 * @author : qinjinyuan
 * @desc : 内容管理服务
 * @date : 2023/10/30 15:39
 */
@Service
@Slf4j
public class DataRemoveManager {
    @Autowired
    private IBrandTasteEvaluateService evaluateService;
    @Autowired
    private IMyStatisticsService myStatisticsService;
    @Autowired
    private IStoreService storeService;
    @Autowired
    private IStoreFollowService storeFollowService;
    @Autowired
    private IBrandTasteEvaluateReplyService evaluateReplyService;
    @Autowired
    private IBrandTasteService brandTasteService;
    @Autowired
    private BrandTasteMapper brandTasteMapper;
    @Autowired
    private BrandTasteCacheService brandTasteCache;
    @Autowired
    private IUserActionService userActionService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private IArticleEvaluateService articleEvaluateService;
    @Autowired
    private IArticleEvaluateReplyService articleReplyService;
    @Autowired
    private ReceivedLikesCacheService receivedLikesCache;

    /**
     * 删除产品
     *
     * @param req
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteProduct(ProductDeleteReq req) {
        if (CharSequenceUtil.isBlank(req.getBrandTasteIds())) {
            throw new ServiceException("delete BrandTasteIds is empty.");
        }
        List<String> brandTasteIdList = Arrays.asList(req.getBrandTasteIds().split(","));
        if (brandTasteIdList.size() > 500) {
            throw new ServiceException("delete BrandTasteIds size is bigger then 500.");
        }

        LambdaQueryWrapper<BrandTaste> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.select(BrandTaste::getBrandTasteId, BrandTaste::getQrExportNum).eq(BrandTaste::getDeletedVersion, 0L).eq(BrandTaste::getSource, 0)
                .in(BrandTaste::getBrandTasteId, Arrays.asList(req.getBrandTasteIds().split(",")));
        List<BrandTaste> list = brandTasteService.list(lambdaQueryWrapper);
        list.forEach(item -> item.setDeletedVersion(item.getBrandTasteId()));

        // 如果有二维码数据，则不能进行删除
        list.forEach(item -> {
            if (Objects.nonNull(item.getQrExportNum()) && item.getQrExportNum() > 0) {
                throw new ServiceException("the product had qrCode data,do not delete");
            }
        });
        // 批量更新
        boolean flag = brandTasteService.updateBatchById(list);
        if (flag) {
            // 同步删除缓存
            String[] brandTasteIds = req.getBrandTasteIds().split(",");
            for (String brandTasteId : brandTasteIds) {
                brandTasteCache.removeBrandTasteCache(brandTasteId);
            }
        }
        List<Long> brandTasteIds = brandTasteIdList.stream().map(Long::parseLong).collect(Collectors.toList());
        removeActionAndStatics(brandTasteIds);
        // 删除评价
        removeEvaluateByProduct(brandTasteIds);
        return flag;
    }

    /**
     * 删除(评价、发布的店铺、回复)
     * <p>
     * 生产环境-收藏的评论，如果后台删除该评论后，前端点击后报异常错误
     *
     * @param req
     * @return
     */
    public boolean deleteByObjId(ContentDeleteReq req) {
        ReportBusinessTypeEnum reportBusinessTypeEnum = ReportBusinessTypeEnum.getEnum(req.getBusinessType());
        if (Objects.isNull(reportBusinessTypeEnum)) {
            throw new ServiceException("businessType is not exist");
        }
        // 删除 产品，评价及关联数据
        boolean flag;
        List<Long> objectIds = Lists.newArrayList();
        objectIds.add(req.getObjectId());
        switch (reportBusinessTypeEnum) {
            case PRODUCT:
                flag = brandTasteMapper.update(BrandTaste.builder().deletedVersion(req.getObjectId()).build(), new LambdaQueryWrapper<BrandTaste>()
                        .eq(BrandTaste::getBrandTasteId, req.getObjectId())
                        .eq(BrandTaste::getSource, SOURCE_USER_EVALUATE)
                        .eq(BrandTaste::getDeletedVersion, 0)
                ) > 0;
                if (flag) {
                    brandTasteCache.removeBrandTasteCache(String.valueOf(req.getObjectId()));
                }
                removeActionAndStatics(objectIds);
                // 删除评价
                removeEvaluateByProduct(objectIds);
                return flag;
            case STORE:
                removeStoreByIds(objectIds);
                return true;
            case EVALUATE:
                // 删除评价
                removeEvaluateByIds(objectIds);
                return true;
            case EVALUATE_REPLY:
                removeReplyByIds(objectIds);
                return true;
            default:
                return false;
        }
    }

    public void deleteArticleByObjId(List<Long> objectIds) {
        // 删除 产品，评价及关联数据
        removeActionAndStatics(objectIds);
        // 收到的点赞统计数据refresh
        receivedLikesCache.loadData();
        // 删除评价
        removeEvaluateByArticle(objectIds);
    }

    /**
     * 根据产品删除对应评价数据
     *
     * @param brandTasteIdList
     * @return
     */
    private void removeEvaluateByProduct(List<Long> brandTasteIdList) {
        if (CollUtil.isEmpty(brandTasteIdList)) {
            return;
        }
        List<BrandTasteEvaluate> evaluates = evaluateService.list(new LambdaQueryWrapper<BrandTasteEvaluate>()
                .select(BrandTasteEvaluate::getEvaluateId)
                .in(BrandTasteEvaluate::getBrandTasteId, brandTasteIdList)
                .eq(BrandTasteEvaluate::getDeletedVersion, 0L)
        );
        if (CollUtil.isEmpty(evaluates)) {
            return;
        }
        List<Long> evaluateIds = evaluates.stream().map(BrandTasteEvaluate::getEvaluateId).collect(Collectors.toList());
        // 删除评价对应的 回复及统计数据
        removeReply(evaluateIds);

        removeActionAndStatics(evaluateIds);

        // 删除产品对应的评价数据
        evaluateService.update(new LambdaUpdateWrapper<BrandTasteEvaluate>()
                .setSql("  deleted_version = evaluate_id ")
                .set(BrandTasteEvaluate::getUpdatedTime, new Date())
                .set(BrandTasteEvaluate::getUpdatedBy, SecurityUtils.getUserId())
                .in(BrandTasteEvaluate::getBrandTasteId, brandTasteIdList)
                .eq(BrandTasteEvaluate::getDeletedVersion, 0L));
    }

    /**
     * 根据产品删除对应评价数据
     *
     * @param articleIds
     * @return
     */
    private void removeEvaluateByArticle(List<Long> articleIds) {
        if (CollUtil.isEmpty(articleIds)) {
            return;
        }
        List<ArticleEvaluate> evaluates = articleEvaluateService.list(new LambdaQueryWrapper<ArticleEvaluate>()
                .select(ArticleEvaluate::getArticleEvaluateId)
                .in(ArticleEvaluate::getArticleId, articleIds)
                .eq(ArticleEvaluate::getDeletedVersion, 0L)
        );
        if (CollUtil.isEmpty(evaluates)) {
            return;
        }
        List<Long> evaluateIds = evaluates.stream().map(ArticleEvaluate::getArticleEvaluateId).collect(Collectors.toList());
        // 删除评价对应的 回复及统计数据
        removeArticleReply(evaluateIds);

        removeActionAndStatics(evaluateIds);
        // 删除产品对应的评价数据
        articleEvaluateService.update(new LambdaUpdateWrapper<ArticleEvaluate>()
                .setSql("  deleted_version = article_evaluate_id ")
                .set(ArticleEvaluate::getUpdatedTime, new Date())
                .set(ArticleEvaluate::getUpdatedBy, SecurityUtils.getUserId())
                .in(ArticleEvaluate::getArticleId, articleIds)
                .eq(ArticleEvaluate::getDeletedVersion, 0L));
    }

    private void removeArticleReply(List<Long> evaluateIds) {
        if (CollUtil.isEmpty(evaluateIds)) {
            return;
        }
        // 删除评价对应的 回复及统计数据
        List<List<Long>> evaluateIdsList = Lists.partition(evaluateIds, 1000);
        List<Long> replyIds = Lists.newArrayList();
        for (List<Long> itemIds : evaluateIdsList) {
            List<ArticleEvaluateReply> evaluateReplyList = articleReplyService.list(new LambdaQueryWrapper<ArticleEvaluateReply>()
                    .select(ArticleEvaluateReply::getArticleEvaluateReplyId)
                    .in(ArticleEvaluateReply::getArticleEvaluateId, itemIds)
                    .eq(ArticleEvaluateReply::getDeletedVersion, 0L));
            List<Long> curReplyIds = evaluateReplyList.stream().map(ArticleEvaluateReply::getArticleEvaluateReplyId).collect(Collectors.toList());
            replyIds.addAll(curReplyIds);
        }
        if (CollUtil.isEmpty(replyIds)) {
            return;
        }
        removeArticleReplyByIds(replyIds);
    }

    /**
     * 删除评价回复
     *
     * @param evaluateIds
     */
    private void removeReply(List<Long> evaluateIds) {
        if (CollUtil.isEmpty(evaluateIds)) {
            return;
        }
        // 删除评价对应的 回复及统计数据
        List<BrandTasteEvaluateReply> evaluateReplyList = evaluateReplyService.list(new LambdaQueryWrapper<BrandTasteEvaluateReply>()
                .select(BrandTasteEvaluateReply::getEvaluateReplyId)
                .in(BrandTasteEvaluateReply::getEvaluateId, evaluateIds)
                .eq(BrandTasteEvaluateReply::getDeletedVersion, 0L));
        List<Long> replyIds = evaluateReplyList.stream().map(BrandTasteEvaluateReply::getEvaluateId).collect(Collectors.toList());
        if (CollUtil.isEmpty(replyIds)) {
            return;
        }
        removeReplyByIds(replyIds);
    }

    private void removeReplyByIds(List<Long> replyIds) {
        if (CollUtil.isEmpty(replyIds)) {
            return;
        }
        removeActionAndStatics(replyIds);
        evaluateReplyService.update(new LambdaUpdateWrapper<BrandTasteEvaluateReply>()
                .setSql("  deleted_version = evaluate_reply_id ")
                .set(BrandTasteEvaluateReply::getUpdatedTime, new Date())
                .set(BrandTasteEvaluateReply::getUpdatedBy, SecurityUtils.getUserId())
                .in(BrandTasteEvaluateReply::getEvaluateReplyId, replyIds)
                .eq(BrandTasteEvaluateReply::getDeletedVersion, 0L));
    }

    private void removeArticleReplyByIds(List<Long> replyIds) {
        if (CollUtil.isEmpty(replyIds)) {
            return;
        }
        removeActionAndStatics(replyIds);

        // 批量处理，防止数据过大，导致SQL执行异常
        List<List<Long>> replyIdsList = Lists.partition(replyIds, 1000);
        for (List<Long> itemIds : replyIdsList) {
            articleReplyService.update(new LambdaUpdateWrapper<ArticleEvaluateReply>()
                    .setSql("  deleted_version = article_evaluate_reply_id ")
                    .set(ArticleEvaluateReply::getUpdatedTime, new Date())
                    .set(ArticleEvaluateReply::getUpdatedBy, SecurityUtils.getUserId())
                    .in(ArticleEvaluateReply::getArticleEvaluateReplyId, itemIds)
                    .eq(ArticleEvaluateReply::getDeletedVersion, 0L));
        }
    }

    private void removeEvaluateByIds(List<Long> evaluateIds) {
        if (CollUtil.isEmpty(evaluateIds)) {
            return;
        }
        // 删除评价对应的 回复及统计数据
        removeReply(evaluateIds);

        removeActionAndStatics(evaluateIds);

        // 删除产品对应的评价数据
        evaluateService.update(new LambdaUpdateWrapper<BrandTasteEvaluate>()
                .setSql("  deleted_version = evaluate_id ")
                .set(BrandTasteEvaluate::getUpdatedTime, new Date())
                .set(BrandTasteEvaluate::getUpdatedBy, SecurityUtils.getUserId())
                .in(BrandTasteEvaluate::getEvaluateId, evaluateIds)
                .eq(BrandTasteEvaluate::getDeletedVersion, 0L));
    }

    private void removeStoreByIds(List<Long> storeIds) {
        if (CollUtil.isEmpty(storeIds)) {
            return;
        }
        removeActionAndStatics(storeIds);
        // 删除产品对应的评价数据
        storeService.update(new LambdaUpdateWrapper<Store>()
                .setSql("  deleted_version = store_id ")
                .set(Store::getUpdatedTime, new Date())
                .set(Store::getUpdatedBy, SecurityUtils.getUserId())
                .in(Store::getStoreId, storeIds)
                .eq(Store::getDeletedVersion, 0L));
        // 删除店铺回访记录
        storeFollowService.lambdaUpdate()
                .in(StoreFollow::getStoreId, storeIds)
                .eq(StoreFollow::getDeletedVersion, 0)
                .setSql(" deleted_version=store_follow_id ")
                .update();
        // 对最新的店铺缓存进行清理
        Collection<String> keys = redisService.keys(RedisCacheKey.HISMK_STORE_EVALUATE_LIST_PREFIX + "*");
        for (String key : keys) {
            redisService.deleteObject(key);
        }
    }

    /**
     * 删除用户行为及统计数据
     *
     * @param objectIds
     */
    private void removeActionAndStatics(List<Long> objectIds) {
        if (CollUtil.isEmpty(objectIds)) {
            return;
        }
        List<List<Long>> objectIdsList = Lists.partition(objectIds, 1000);
        Long userId = SecurityUtils.getUserId();
        for (List<Long> itemIds : objectIdsList) {
            // 删除评价对应的用户行为
            userActionService.update(new LambdaUpdateWrapper<UserAction>()
                    .setSql("  deleted_version = user_action_id ")
                    .set(UserAction::getUpdatedTime, new Date())
                    .set(UserAction::getUpdatedBy, userId)
                    .in(UserAction::getObjectId, itemIds)
                    .eq(UserAction::getDeletedVersion, 0L));
            // 删除统计数据
            myStatisticsService.update(new LambdaUpdateWrapper<MyStatistics>()
                    .setSql("  deleted_version = my_statistics_id ")
                    .set(MyStatistics::getUpdatedTime, new Date())
                    .set(MyStatistics::getUpdatedBy, userId)
                    .in(MyStatistics::getObjectId, itemIds)
                    .eq(MyStatistics::getDeletedVersion, 0L));
        }
    }

    public void removeStatics(Long objectId) {
        if (Objects.isNull(objectId)) {
            return;
        }
        // 删除统计数据
        myStatisticsService.update(new LambdaUpdateWrapper<MyStatistics>()
                .setSql("  deleted_version = my_statistics_id ")
                .set(MyStatistics::getUpdatedTime, new Date())
                .set(MyStatistics::getUpdatedBy, SecurityUtils.getUserId())
                .eq(MyStatistics::getObjectId, objectId)
                .eq(MyStatistics::getDeletedVersion, 0L));
    }
}
